#ifndef DWAR_H
#define DWAR_H

#include <Arduino.h>
#include "device/screen.h"
#include "shared_val.h"
#include "./device/haiman_driver.hpp"
#include "BilinearInterpolation.h"
#include "colormap.h"


#define PROB_SCALE 8
unsigned short draw_pixel[PIXEL_PER_COLUMN][PIXEL_PER_ROW] = {0};
int R_colour, G_colour, B_colour;
float ft_point; // 屏幕光标点的温度值
const int biox = 30;
const int bioy = 28;
const int lines = 3;                            // 一次渲染多少行的像素
uint16_t lineBuffer[biox * PROB_SCALE * lines]; // Toggle buffer for lines
uint16_t dmaBuffer1[biox * PROB_SCALE * lines]; // Toggle buffer for lines
uint16_t dmaBuffer2[biox * PROB_SCALE * lines]; // Toggle buffer for lines
uint16_t *dmaBufferPtr = dmaBuffer1;
bool dmaBufferSel = 0;

// void getColour(int j)
//    {
//     if (j >= 0 && j < 30)
//        {
//         R_colour = 0;
//         G_colour = 0;
//         B_colour = 20 + 4 * j;
//        }

//     if (j >= 30 && j < 60)
//        {
//         R_colour = 4 * (j - 30);
//         G_colour = 0;
//         B_colour = 140 - 2 * (j - 30);
//        }

//     if (j >= 60 && j < 90)
//        {
//         R_colour = 120 + 4 * (j - 60);
//         G_colour = 0;
//         B_colour = 80 - 2 * (j - 60);
//        }

//     if (j >= 90 && j < 120)
//        {
//         R_colour = 255;
//         G_colour = 0 + 2 * (j - 90);
//         B_colour = 10 - (j - 90) / 3;
//        }

//     if (j >= 120 && j < 150)
//        {
//         R_colour = 255;
//         G_colour = 60 + 175 * (j - 120) / 30;
//         B_colour = 0;
//        }

//     if (j >= 150 && j <= 180)
//        {
//         R_colour = 255;
//         G_colour = 235 + (j - 150) * 20 / 30;
//         B_colour = 0 + 85 * (j - 150) / 10;
//        }
// }

// 绘制十字
inline void draw_cross(int x, int y, int len)
{
   tft.drawLine(x - len / 2, y, x + len / 2, y, tft.color565(255, 255, 255));
   tft.drawLine(x, y - len / 2, x, y + len / 2, tft.color565(255, 255, 255));

   tft.drawLine(x - len / 4, y, x + len / 4, y, tft.color565(0, 0, 0));
   tft.drawLine(x, y - len / 4, x, y + len / 4, tft.color565(0, 0, 0));
}

// 点测温功能
inline void show_local_temp(float num, int x, int y, int cursor_size)
{
   tft.setRotation(1);
   draw_cross(x, y, 8);
   static short temp_xy;
   static int shift_x, shift_y;
   if (x < 140)
   {
      shift_x = 10;
   }
   else
   {
      shift_x = -60;
   }
   if (y < 120)
   {
      shift_y = 10;
   }
   else
   {
      shift_y = -20;
   }
   tft.setTextSize(cursor_size);
   tft.setCursor(x + shift_x, y + shift_y);
   tft.printf("%.2f", num);
}

// 点测温功能
inline void show_local_temp(float num, int x, int y)
{
   show_local_temp(num, x, y, 2);
}

// 判断应该在什么时候渲染光标（光标位置在当前渲染行数-40行的时候）
// 这么做是为了让光标别闪
inline void insert_temp_cursor(int y)
{
   static int trig_line;
   tft.setRotation(1);
   trig_line = test_point[0] + 80;
   if (trig_line > 215)
   {
      trig_line = 215;
   }
   if (y == trig_line)
   {
      if (flag_show_cursor == true)
      {
         show_local_temp(ft_point, test_point[0], test_point[1]);
      }
   }
   tft.setRotation(0);
}

inline void draw_float_num(int x, int y, float num)
{
   // 定义两个字符串来存储小数点前后的部分
   char integerPart[5];
   char fractionalPart[5];
   // 使用 sprintf 格式化字符串
   sprintf(integerPart, "%d", (int)num);                           // 获取整数部分
   sprintf(fractionalPart, "%02d", (int)((num - (int)num) * 100)); // 获取小数部分
   tft.setCursor(x, y);
   tft.printf("%s.", integerPart);
   tft.setCursor(x + 5, y + 10);
   tft.printf("%s", fractionalPart);
}

inline void draw_percent_num(int x, int y, uint8_t num)
{
   // 定义两个字符串来存储小数点前后的部分
   tft.setCursor(x, y);
   tft.printf("%d%%", num);
}

void draw() {
    static int value;          // 用于临时存储插值后的色彩索引值
    static int now_y = 0;      // 当前已累积的行数（用于 DMA 分块传输）

    // 如果启用了上采样（即使用插值放大图像，提升显示平滑度）
    if (use_upsample) {
        // 设置屏幕旋转为 0（通常为横向或纵向原始方向，与硬件接线对应）
        tft.setRotation(0);

        // 开始批量写入 TFT，提升绘图效率（减少通信开销）
        tft.startWrite();

        // 遍历放大后的图像每一行（原始 32 行 × 缩放因子 PROB_SCALE）
        for (int y = 0; y < 32 * PROB_SCALE; y++) {
            // 遍历每行的每一列（原始 30 列 × 缩放因子 PROB_SCALE）
            // 注：此处为 30 而非 32，可能因传感器有效区域或裁剪（如 MLX90640 实际常用 32x24 或 30x32）
            for (int x = 0; x < 30 * PROB_SCALE; x++) {
                // 使用双线性插值算法，根据 (x, y) 在放大坐标系中的位置，
                // 从原始 32x30 的 draw_pixel 中插值得到平滑的色彩索引
                value = bio_linear_interpolation(x, y, draw_pixel);

                // 将插值后的色彩索引映射为实际的 RGB565 颜色值，并存入行缓冲区
                // 缓冲区按行交错存储：x + now_y * (总宽度)
                lineBuffer[x + now_y * biox * PROB_SCALE] = colormap[value];
            }

            // 当前行处理完毕，行计数器递增
            now_y++;

            // 如果累积行数达到 DMA 传输块大小（lines），则触发一次 DMA 图像推送
            if (now_y == lines) {
                // 双缓冲机制：交替使用 dmaBuffer1 和 dmaBuffer2，避免显示撕裂
                if (dmaBufferSel) {
                    dmaBufferPtr = dmaBuffer2;
                } else {
                    dmaBufferPtr = dmaBuffer1;
                }
                dmaBufferSel = !dmaBufferSel; // 切换下次使用的缓冲区

                // 使用 DMA 高速推送图像块到屏幕：
                // 起始坐标 (0, y - now_y) 即当前块的顶部行，
                // 宽度 = biox * PROB_SCALE（即 30 * PROB_SCALE），
                // 高度 = lines，
                // 数据源 = lineBuffer，
                // 使用指定的 DMA 缓冲区指针
                tft.pushImageDMA(0, y - now_y, biox * PROB_SCALE, lines, lineBuffer, dmaBufferPtr);
                // 重置行计数器，准备下一块
                now_y = 0;
            }

            // 在当前行绘制温度光标（如十字线或圆点），若启用
            // insert_temp_cursor(y);
        }
        // 循环结束后，若还有未推送的剩余行（now_y != 0），则推送最后一块
        if (now_y != 0) {
            if (dmaBufferSel) {
                dmaBufferPtr = dmaBuffer2;
            } else {
                dmaBufferPtr = dmaBuffer1;
            }
            dmaBufferSel = !dmaBufferSel;

            // 推送剩余行：起始 y 坐标为 (总高度 - 剩余行数)
            tft.pushImageDMA(0, 32 * PROB_SCALE - now_y, biox * PROB_SCALE, now_y, lineBuffer, dmaBufferPtr);
            now_y = 0;
        }

        // 结束批量写入
        tft.endWrite();
    } else {
        // 未启用上采样：直接绘制原始像素块（每个传感器像素绘制为 PROB_SCALE × PROB_SCALE 的方块）

        static uint16_t c565; // 临时存储 RGB565 颜色值

        tft.setRotation(0);

        // 注意：此处 i 对应 x（列），j 对应 y（行）
        // 原始数据维度为 30（宽）× 32（高）
        for (int i = 0; i < 30; i++) {
            for (int j = 0; j < 32; j++) {
                // 从 draw_pixel 获取色彩索引，并查表得到 RGB565 颜色
                c565 = colormap[(int)draw_pixel[i][j]];

                // 在屏幕位置 (i*PROB_SCALE, j*PROB_SCALE) 绘制一个 PROB_SCALE×PROB_SCALE 的色块
                tft.fillRect(i * PROB_SCALE, j * PROB_SCALE, PROB_SCALE, PROB_SCALE, c565);
            }
        }
    }
}

// 用来处理画面被暂停时的热成像图层的渲染工作
void freeze_handeler()
{
   // 仅拍照模式下，位于第一屏时会启用这个功能
   if (flag_clear_cursor)
   {
      draw();
      flag_clear_cursor = false;
   } // 通过重新渲染一张画面来清除光标
   if (flag_show_cursor)
   {
      show_local_temp(ft_point, test_point[0], test_point[1]);
   } // 每次点击都渲染光标位置
}

// 探头准备期间的渲染管线
void preparing_loop()
{
   tft.setRotation(1);
   if (prob_status == PROB_CONNECTING)
   {
      tft.setCursor(20, 200);
      tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
      tft.setTextSize(1);
      tft.fillRect(20, 200, 240, 30, TFT_BLACK);
      tft.printf("Triying to connect to HTPAd");
      tft.setCursor(20, 210);
      tft.printf("address: %d\n", SENSOR_ADDRESS);
      delay(10);
   }
   else if (prob_status == PROB_INITIALIZING)
   {
      tft.setCursor(20, 200);
      tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
      tft.setTextSize(1);
      tft.fillRect(20, 200, 240, 30, TFT_BLACK);
      tft.printf("HTPAd is ready, initializing...\n");
      delay(10);
   }
   else if (prob_status == PROB_PREPARING)
   {
      tft.setCursor(20, 200);
      tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
      tft.setTextSize(1);
      tft.fillRect(20, 200, 240, 30, TFT_BLACK);
      tft.printf("HTPAd initializing... \n");
      delay(10);
   }
}

// 探头准备期间的渲染管线
void refresh_status()
{
   tft.setCursor(20, 200);
   tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
   tft.setTextSize(1);
   tft.fillRect(20, 200, 240, 30, TFT_BLACK);
   tft.printf("prepering touch panel...");
   delay(10);
}

// 处理tft_espi渲染管线
// 处理tft_espi渲染管线
void screen_loop()
{
   // 如果当前不在拍照模式（即处于正常热成像显示模式）
   if (!flag_in_photo_mode)
   {
      // 等待探头数据锁释放（避免在读取过程中被其他任务修改）
      unsigned long wait_start = millis();
      while (prob_lock == true)
      {
         delay(1);
         // 添加超时机制防止无限等待
         if (millis() - wait_start > 100) {
             logln("Timeout waiting for prob_lock");
             break;
         }
      }
      // 确保有有效的温度数据
      if (T_max == 0 && T_min == 0) {
          logln("No valid temperature data");
          return;
      }

      // 获取像素数据拷贝锁，防止在拷贝过程中被中断修改
      pix_cp_lock = true;

      // 获取指定测试点（test_point）的温度值，并转换为摄氏度
      // 添加边界检查
      int test_x = test_point[0] / PROB_SCALE;
      int test_y = (test_point[1] / PROB_SCALE) + 2;
      
      // 确保索引在有效范围内
      if (test_x >= 0 && test_x < 32 && test_y >= 0 && test_y < 32) {
          ft_point = (float)(data_pixel[test_x][test_y] / 10) - 273.15;
      }
      
      // 遍历 32x32 的热成像像素阵列
      for (int i = 0; i < 32; i++)
      {
         for (int j = 0; j < 32; j++)
         {
            // 添加零值检查
            if (T_max != T_min) {
                // 将原始温度值线性映射到 0~180 的色彩索引范围（用于伪彩色映射）
                unsigned short value = (180 * (data_pixel[i][j] - T_min) / (T_max - T_min));
                if (value < 180)
                {
                   draw_pixel[i][j] = value; // 存入用于显示的像素缓冲区
                }
            } else {
                // 如果最大值等于最小值，使用默认值
                draw_pixel[i][j] = 0;
            }
         }
      }

      // 释放像素拷贝锁
      pix_cp_lock = false;
      // 等待色谱（colormap）加载完成，避免在加载过程中读取错误数据
      wait_start = millis();
      while (cmap_loading_lock == true)
      {
         delay(1);
         // 添加超时机制
         if (millis() - wait_start > 100) {
             logln("Timeout waiting for colormap");
             break;
         }
      }
      // 执行主热成像画面绘制（将 draw_pixel 渲染到屏幕）
      draw();
      // 设置屏幕旋转方向（根据硬件安装方向调整）
      tft.setRotation(1);

      // 设置字体大小
      tft.setTextSize(1);

      // 显示温度信息
      float ft_max = float(T_max) / 10 - 273.15; // 最高温度（℃）
      float ft_min = float(T_min) / 10 - 273.15; // 最低温度（℃）
      
      // 显示“max”标签（红色，表示最高温）
      tft.setCursor(258, 32);
      tft.setTextColor(TFT_RED);
      tft.printf("max");

      // 显示“min”标签（蓝色，表示最低温）
      tft.setTextColor(TFT_BLUE);
      tft.setCursor(258, 110);
      tft.printf("min");

      // 显示“Bat”标签（绿色，表示电池电量）
      tft.setTextColor(TFT_GREEN);
      tft.setCursor(258, 195);
      tft.printf("Bat");

      // 设置文字背景为黑色，前景为白色，启用背景填充（避免残影）
      tft.setTextColor(TFT_WHITE, TFT_BLACK, true);

      // 在指定位置绘制最高温度数值
      draw_float_num(258, 47, ft_max);
      // 绘制最低温度数值
      draw_float_num(258, 125, ft_min);
      // 绘制电池电量百分比
      draw_percent_num(258, 210, vbat_percent);
      // 如果启用了光标显示，则在屏幕上标注测试点的温度
      if (flag_show_cursor == true)
      {
         show_local_temp(ft_point, test_point[0], test_point[1]);
      }
   }
   else
   {
      // 如果处于拍照模式，则调用冻结画面处理函数（如显示静态图像、禁用刷新等）
      freeze_handeler();
   }
}
#endif